#include <iostream>
using namespace std;
struct edgenode
{
    long long weight;
    int vertex1;
    int vertex2;
} edge[5000000];
class minHeap
{
private:
    edgenode *heap; // 元素数组
    int heapSize;   // 堆中的元素个数
public:
    minHeap(int n)
    {
        heapSize = 0;
        heap = new edgenode[n + 1];
    }
    ~minHeap() { delete[] heap; }
    bool empty() { return heapSize == 0; } // 判断heapSize是否为0.
    int Size() { return heapSize; }        // 返回heapSize的值
    edgenode top() { return heap[1]; }     // 输出根
    void pop();
    void initialize(edgenode *theheap, int theSize);
};
void minHeap::pop()
{                                            // 删除
    edgenode lastElement = heap[heapSize--]; // 最后一个元素
    int currentNode = 1;                     // 从当前被删掉的最小元素的位置开始
    int child = 2;                           // currentNode的孩子
    while (child <= heapSize)
    {
        if (child < heapSize && heap[child].weight > heap[child + 1].weight)
            child++; // 找到左右孩子中更小的
        if (lastElement.weight <= heap[child].weight)
            break;                       // 当孩子比要插入的大，则可以插入了，跳出循环
        heap[currentNode] = heap[child]; // 将较小的孩子上移
        currentNode = child;             // currentNode向下移
        child *= 2;
    }
    heap[currentNode] = lastElement;
}
void minHeap::initialize(edgenode *theHeap, int theSize)
{ // 初始化
    delete[] heap;
    heap = new edgenode[theSize + 1];
    for (int i = 1; i <= theSize; i++)
    {
        heap[i] = theHeap[i];
    }
    heapSize = theSize;
    for (int root = heapSize / 2; root >= 1; root--)
    {                                      // 从数组中最右一个有孩子的节点开始
        edgenode rootElement = heap[root]; // 子树的根
        int child = 2 * root;              // rootElement的孩子位置
        while (child <= heapSize)
        {
            if (child < heapSize && heap[child].weight > heap[child + 1].weight)
                child++; // 找到孩子里较小的
            if (rootElement.weight <= heap[child].weight)
                break; // 如果子树的根小于其孩子，则可以跳出循环
            // 如果孩子较小
            heap[child / 2] = heap[child]; // 将孩子上移
            child *= 2;
        }
        heap[child / 2] = rootElement;
    }
}

int parent[2000000] = {0};
int find(int theelement)
{
    int root = theelement;
    while (parent[root] != 0)
    { // 找根
        root = parent[root];
    }
    while (theelement != root)
    { // 将所有的点都连到根上，降低高度
        int t = parent[theelement];
        ;
        parent[theelement] = root;
        theelement = t;
    }
    return root;
}
void unite(int a, int b)
{ // 两个树合并
    parent[b] = a;
}
int main()
{
    int n, e;
    cin >> n >> e;
    for (int i = 1; i <= e; i++)
    { // 结构体数组
        cin >> edge[i].vertex1 >> edge[i].vertex2 >> edge[i].weight;
        int t = 0;
    }
    int k = 0;
    long long sumw = 0;
    minHeap heap(1); // 最小堆
    heap.initialize(edge, e);
    while (e > 0 && k < n - 1)
    {
        edgenode x = heap.top();
        heap.pop();
        e--;
        int a = find(x.vertex1); // 找该边两个顶点的根
        int b = find(x.vertex2);
        if (a != b)
        { // 如果不在同一个集合，进行合并
            unite(a, b);
            k++;
            sumw += x.weight;
        }
    }
    cout << sumw << endl;
    return 0;
}